package com.springboot.fram.core.utils;

import java.beans.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @author liheng
 * @ClassName ClassUtils
 * @Description
 * @date 2021-08-28 17:51
 */
public class ClassUtils {
    /**
     * 代理 class 的名称
     */
    private static final List<String> PROXY_CLASS_NAMES = Arrays.asList(
            // cglib
            "net.sf.cglib.proxy.Factory",
            "org.springframework.cglib.proxy.Factory",
            // javassist
            "javassist.util.proxy.ProxyObject",
            "org.apache.ibatis.javassist.util.proxy.ProxyObject"
    );

    /**
     * <p>
     * 获取该类的所有属性列表
     * Transient.class
     * 需要忽略的字段
     * </p>
     *
     * @param clazz 反射类
     */
    public static List<Field> getFieldList(Class<?> clazz) {
        Class current = getProxyTargetClass(clazz);
        Map<String, Field> map = new HashMap<>(8);
        while (current.getSuperclass() != null && current != Object.class) {
            Field[] fields = current.getDeclaredFields();
            Transient trans;
            for (Field field : fields) {
                trans = field.getAnnotation(Transient.class);
                boolean transFlag = (trans == null || (trans != null && trans.value()));
                if (!isStatic(field) && transFlag && !map.containsKey(field.getName())) {
                    map.put(field.getName(), field);
                }
            }
            current = current.getSuperclass();
        }
        return new ArrayList<>(map.values());
    }

    /**
     * 过滤 static 和 transient 关键字修饰的属性
     *
     * @param field Field
     * @return true: field is static modifier
     */
    private static boolean isStatic(Field field) {
        return Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers());
    }

    /**
     * <p>
     * 获取代理对象的target class
     * </p>
     *
     * @param clazz 传入
     * @return 如果是代理的class，返回父 class，否则返回自身
     */
    public static Class<?> getProxyTargetClass(Class<?> clazz) {
        if (clazz != null) {
            for (Class klass : clazz.getInterfaces()) {
                if (PROXY_CLASS_NAMES.contains(klass.getName())) {
                    return clazz.getSuperclass();
                }
            }
        }
        return clazz;
    }


    /**
     * 确定class是否可以被加载
     * ClassLoader classLoader = HttpUtil.class.getClassLoader();
     * <p>
     * if (ClassUtils.loader("java.net.http.HttpClient", classLoader))
     *
     * @param className   完整类名
     * @param classLoader 类加载
     * @return {boolean}
     */
    public boolean loader(String className, ClassLoader classLoader) {
        try {
            Class.forName(className, true, classLoader);
            return true;
        } catch (Throwable ex) {
            return false;
        }
    }
}
